<?php

namespace C\S\Casher;

use C\L\Service;
use C\M\WithdrawLog;
use C\M\User;
use C\M\UserBank;
use C\M\GroupBuyingOrder;

class Withdraw extends Service
{
    protected function setModel()
    {
        $this->model = new WithdrawLog();
    }

  /**
   * 提现申请
   *
   * @param int $userId
   * @param int $bankId
   * @param double $amount
   * @return bool
   **/
    public function apply($userId, $bankId, $amount)
    {
      // 验证最小提现金额
        $config = $this->di['s_config']->get('pay');
        $minAmount = $config['cost_min_money'] ?? 0;
        if ($minAmount > $amount) {
            throw new \Exception('最小提现金额为' . $minAmount);
        }

      // 验证用户
        $user = User::findFirst([
        'conditions' => 'uid = :user_id:',
        'bind'       => ['user_id' => $userId],
        ]);
        if (!$user) {
            throw new \Exception("用户不存在");
        }

      // 验证余额是否足够
        if ($user->money < $amount) {
            throw new \Exception('余额不足');
        }

      // 验证有效订单数
        $count = GroupBuyingOrder::count([
        'conditions' => 'user_id = :user_id:',
        'bind'       => ['user_id' => $userId],
        ]);
        if ($count <= 0) {
            throw new \Exception('无有效发起订单');
        }

      // 验证银行卡
        $bank = UserBank::findFirst([
        'conditions' => 'id = :id: And uid = :user_id:',
        'bind' => [
        'id'      => $bankId,
        'user_id' => $userId,
        ],
        ]);
        if (!$bank) {
            throw new \Exception("提现账户不存在");
        }

        try {
            $this->di['db']->begin();
          // 生成提现记录
            $withdrawLog = new WithdrawLog;
            $withdrawLog->user_id      = $userId;
            $withdrawLog->user_bank_id = $bankId;
            $withdrawLog->amount       = $amount;
            $withdrawLog->state        = 'pending';
            if (!$withdrawLog->save()) {
                throw new \Exception('提现申请失败');
            }

          // 更新余额并添加流水
            if (!$this->di['s_user']->updateBalance(
                $userId,
                -$amount,
                'withdraw',
                '余额提现',
                $withdrawLog->id,
            )) {
                throw new \Exception('更新用户余额失败');
            }

            $this->di['db']->commit();
            return true;
        } catch (\Exception $error) {
            if ($this->di['db']->isUnderTransaction()) {
                $this->di['db']->rollback();
            }

            throw $error;

            return false;
        }
    }

  /**
   * 设置提现状态
   *
   * @param int $id
   * @return mixed
   **/
    public function updateState($id, $state)
    {
        $params = [
        'id = :id:',
        'bind' => ['id' => $id]
        ];
        $withdrawLog = WithdrawLog::findFirst($params);
        if ($state != 'pending' && $withdrawLog->state != 'pending') {
            throw new \Exception('提现记录状态异常');
        }

        try {
            $this->di['db']->begin();

            $withdrawLog->state = $state;
            if (!$withdrawLog->save()) {
                throw new \Exception('更新提现记录状态失败');
            }

            if ($withdrawLog->state == 'failure' &&
            !$this->di['s_user']->updateBalance(
                $withdrawLog->user_id,
                $withdrawLog->amount,
                'withdraw_refund',
                '余额返还',
                $withdrawLog->id,
            )
            ) {
                throw new \Exception('更新用户余额失败');
            }

            $this->di['db']->commit();
        } catch (\Exception $error) {
            if ($this->di['db']->isUnderTransaction()) {
                $this->di['db']->rollback();
            }

            throw $error;

            return false;
        }

      // 发送用户提现消息
        switch ($state) {
            case 'success':
                $this->sendMessage('withdraw_success', $withdrawLog);
                break;
            case 'failure':
                $this->sendMessage('withdraw_failure', $withdrawLog);
                break;
            default:
                break;
        }

        return true;
    }

    private function sendMessage($type, $withdrawLog)
    {
        $this->di['s_message']->sendMessageToUser(
            $withdrawLog->user_id,
            $type,
            [
            '__amount__' => $withdrawLog->amount,
            '__time__'   => $withdrawLog->updated_at,
            ],
        );
    }
}
